
Howler는 웹에서의 오디오 제어를 위한 라이브러리로 좋은 성능에 다양한 기능을 지원한다.
특히 괴담집 프로젝트에 필요한 fade
효과나 loop
효과 그리고 여러 소리에 대한 개별 제어등 딱 알맞는 라이브러리라고 생각된다.
이후에 업데이트할 때에는 공간음향같은 Howler.js
에서 제공하는 특수효과도 사용하여 속삭임같은 무서운 음향효과를 구현할수도 있을것 같다는 생각이다.
기본 사용법#
Typescripttypescript
howler는 기본적으로 두가지 객체를 통해 소리를 로드하고 제어한다.
Howl
:Howl
은 개별 사운드에 대한 객체이며 해당 객체를 통해 각각의 소리를 제어할 수 있다.Howler
:Howler
는 글로벌 제어를 위한 객체이며 전체 볼륨제어와 같은 전체 사운드에 대한 제어를 가능하게 한다.
React에서의 사용#
React TSXtsx
에셋을 불러오는 작업과 React의 리렌더링은 수많은 메모리 누수를 일으킬 수 있다. 따라서 사운드를 불러오기 위해선 useRef
를 활용하는것이 가장 좋다.
useRef를 사용하지 않았을때의 문제#
❌ useRef 없이 일반 변수 사용:#
React TSXtsx
문제 시나리오:
- "재생" 클릭 → 소리 재생 시작
- setCount → 컴포넌트 리렌더링
- let sound = null 다시 실행 → 이전 Howl 인스턴스 참조 잃음
- "정지" 클릭 → sound는 null이라 에러!
- 오디오는 백그라운드에서 계속 재생 (제어 불가)
❌ useState 사용:#
React TSXtsx
- UI변경이 없어 리렌더링이 불필요 한데도 소리의 변경 때문에 리렌더링이 발생할 수 있음.
- UI와 무관한 값은 ref에 저장한다는 철학에 위배됨ㄴ
✅ useRef 사용 (올바른 방법):#
React TSXtsx
본격적인 사용을 위한 고민#
Howler.js
를 잘 사용하기 위해서 그리고 앱에서 아무 문제 없도록 사용하기 위해서 React와 관련된 몇가지 문제를 생각해 보아야 한다.
- 인스턴스 문제
- 사운드의 캐싱 문제
- 중복 로딩 문제
리엑트의 생명주기와의 충돌때문에 보편적으로 위와 같은 문제가 발생할 수 있다. howler 인스턴스에 대한 제어권을 잃어버릴수 있고 메모리 누수로 이어질 수 있으며 이미 캐싱이 되어있는데 다시 시도할수도 있고 여러가지 문제가 발생할 수 있다.
따라서 Class
형식을 통해 싱글톤 패턴을 구현하여 추상화하고 추상화된 모듈을 훅을 통하여 접근할 수 있도록 하는게 좋을것이라고 판단된다.
AudioManager 만들기#
Typescripttypescript
캐싱 문제와 인스턴스 문제를 해결하기 위해 싱글톤 패턴의 클래스를 하나 만든다. 클래스를 통해서 관련 기능들을 하나로 묶을 수 있고, private을 통해 보호할 수 있다.
캐싱 시스템 구현하기#
Typescripttypescript
오디오의 캐싱과 중복 로딩을 방지하기 위해 private으로 map자료구조의 변수를 선언해준다.
프리로드 기능#
Typescripttypescript
넘겨받을 에셋의 타입을 정의하고 해당 정보를 등록한다. 이때 존재한다면 이미 존재하는걸 반환해야 한다.
로직의 큰 구조는 먼저 캐시 혹은 로딩중인것 즉 메모리를 먼저 확인하여 현재 작업해야하는 에셋과 비교한 이후에 있다면 현재 저장된 데이터를 반환하고 그렇지 않다면 loadAudioAsset
을 활용해 howl
객체를 만든다. 해당 객체가 load 되면 onload
메소드를 통해 Promise의 결과값을 위한 resolve({howl,asset,loadedAt})
을 반환한다.
제어 기능들#
Typescripttypescript
이제 기본적인 제어에 대한 구현은 완료 되었다. 실제로 이 모듈이 어떻게 사용될지는 구조를 조금 더 살펴보면서 정해야 할것으로 보인다.